package edu.colorado.karl.databases;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Database to monitor and track errors.  The Errors Database already has all
 * possible error messages entered.  Each row contains one of the possible
 * error messages, a start timestamp, a last timestamp, and a flag.
 * <p>If the flag is 1, the error message in that row is displayed on the web 
 * site, or in other words, that error is active.  An error with a flag of 0
 * is considered inactive.
 * <p>When an error occurs, if the flag is 0, both the start and end timestamp
 * fields are filled in with the error's timestamp, and the flag is set to 1.
 * If the flag is already 1, only the last timestamp is filled in.  The start
 * timestamp should be interpreted as the time the error became active.  
 * The last timestamp should be interpreted as the last time the error has 
 * occurred.
 * <p>The database access methods are accessed statically.  An instance of
 * ErrorDatabaseResult acts as a response from the Errors Database to the web
 * site, containing information about an active error.
 */
public class ErrorDatabaseResult {
	/**
	 * Row number of the error in the database.
	 */
	public int errorNumber;
	/**
	 * The error message of the error.
	 */
	public String message;
	/**
	 * Time this error was activated.
	 */
	public String firstTime;
	/**
	 * Time this error last occurred.
	 */
	public String lastTime;
	/**
	 * 1 if the error is active, 0 if not.
	 */
	public int flag;

	/**
	 * Creates and initializes an Error Database response.
	 * @param errorNumber The number of the error row in the database.
	 * @param message The actual error message.
	 * @param firstTime The time the error became active.
	 * @param lastTime The last time the error occurred.
	 * @param flag 1 if the error is active.
	 */
	public ErrorDatabaseResult(int errorNumber, String message, String firstTime, 
			String lastTime, int flag) {
		super();
		this.errorNumber = errorNumber;
		this.message = message;
		this.firstTime = firstTime;
		this.lastTime = lastTime;
		this.flag = flag;
	}
	/**
	 * Error number for the Reach RSS error
	 */
	static public int REACH_RSS=1;

	/**
	 * Error number for the Parse RSS error
	 */
	static public int PARSE_RSS=2;
	
	/**
	 * Error number for the WecCTRL Fail error
	 */
	static public int WEBCTRL_FAIL=3;
	
	/**
	 *  Error number for the Long Term Database Fail error
	 */
	static public int LONG_TERM_FAIL=4;
	
	/**
	 *  Error number for the Setpoints Database Fail error
	 */
	static public int SETPOINTS_FAIL=5;
	
	/**
	 *  Error number for the User Database Fail error
	 */
	static public int USERS_FAIL=6;
	
	/**
	 * Creates a list of all ErrorDatabaseResults that are active.
	 * @return List of all active errors.
	 */
	
	static public List<ErrorDatabaseResult> getActiveErrors() {
		// List of responses
		ArrayList<ErrorDatabaseResult> l = new ArrayList<ErrorDatabaseResult>();
		// Database connection
		Connection c = ErrorDatabaseConnector.getConnection();
		
		if(c == null) {
			return l;	// Return empty list, error already logged
		}
		
		//	Pull the values from the database
		try {
			Statement s = c.createStatement();
			s.executeQuery("select * from Errors where Flag = 1;");
			ResultSet rs = s.getResultSet();
			
			while(rs.next()) {
				l.add(new ErrorDatabaseResult(rs.getInt(1),rs.getString(2),
						rs.getString(3),rs.getString(4),rs.getInt(5)));
				log.debug(rs.getString(2));
			}
			
		} catch (SQLException e) {
			log.warn("ErrorDB: SQL Exception", e);
		}
		
		ErrorDatabaseConnector.closeConnection(c);
		
		return l;
	}

	/**
	 * Activates the specified error in the database.  ErrorNumber should be 
	 * one of the publicly defined constants for this class.
	 * @param errorNumber Number of error that needs to be activated.
	 */
	static public void activateError(int errorNumber)
	{
		if(errorNumber < 1 || errorNumber > 6){
			log.warn("Error out of bounds, Error not logged.");
			return;
		}
		Connection c = ErrorDatabaseConnector.getConnection();
		Calendar cal = Calendar.getInstance();
		Timestamp time = new Timestamp(cal.getTimeInMillis());
		
		if(c == null) {
			return;	// Return empty list, error already logged
		}
		
		try{
			Statement s = c.createStatement();
			s.execute("select * from Errors where Error_Number = " +
					errorNumber + ";");
			ResultSet rs = s.getResultSet();
			if(rs.next()){
				if(rs.getInt(5)==0){
					s=c.createStatement();
					s.executeUpdate("update Errors set Flag = 1, " +
							"First_Time = \"" + time.toString() + "\"," +
							"Last_Time = \"" + time.toString() +
							"\" where Error_Number = " + errorNumber +";");
				}
				else
				{
					s.executeUpdate("update Errors set Last_Time = \"" 
							+ time.toString() +
							"\" where Error_Number = " + errorNumber +";");
				}
			}
		} catch (SQLException e) {
			log.warn("ErrorDB: SQL Exception",e);
		}
		ErrorDatabaseConnector.closeConnection(c);
		
	}
	
	/**
	 * Deactivates the error with the number given.  ErrorNumber should be one
	 * of the publicly declared constants in this class.
	 * @param errorNumber Number of error that needs to be deactivated.
	 */
	static public void deactivateError(int errorNumber)
	{
		if(errorNumber < 1 || errorNumber > 6){
			log.warn("Error out of bounds, Error not deactivated.");
			return;
		}
		log.debug("Removing error #"+errorNumber);
		Connection c = ErrorDatabaseConnector.getConnection();
		if(c == null) {
			return;	// Return empty list, error already logged
		}
		
		try{
			Statement s = c.createStatement();

			s.executeUpdate("update Errors set Flag = 0 " +
					"where Error_Number = " + errorNumber +";");
		} catch (SQLException e) {
			log.warn("ErrorDB: SQL Exception, Could not deactivate "+errorNumber,e);
		}
		ErrorDatabaseConnector.closeConnection(c);
	}
	
	//used for log4j logging
	private static final Log log = LogFactory.getLog(ErrorDatabaseResult.class);
}
